package com.neo4j.neo4jcloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.neo4j.neo4jcloud.common.property.Neo4jProperty;
import com.neo4j.neo4jcloud.entity.CompanyGraph;
import com.neo4j.neo4jcloud.entity.SupplyGraph;
import com.neo4j.neo4jcloud.entity.SupplyRelationShip;
import com.neo4j.neo4jcloud.mapper.SupplyRelationShipRepository;
import com.neo4j.neo4jcloud.service.CompanyGraphService;
import com.neo4j.neo4jcloud.service.SupplyGraphService;
import com.neo4j.neo4jcloud.service.SupplyRelationShipService;
import org.neo4j.driver.*;
import org.neo4j.driver.internal.InternalNode;
import org.neo4j.driver.types.Relationship;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author kabuqinuo
 * @date 2020/3/26 14:13
 */
@Service
public class SupplyRelationShipServiceImpl implements SupplyRelationShipService {

    @Autowired
    private SupplyRelationShipRepository supplyRelationShipRepository;
    @Autowired
    private SupplyGraphService supplyGraphService;
    @Autowired
    private CompanyGraphService companyGraphService;
    @Autowired
    private Neo4jProperty neo4jProperty;


    @Override
    public SupplyRelationShip addSupplyRelationShip(SupplyRelationShip supplyRelationShip) {
        return supplyRelationShipRepository.save(supplyRelationShip);
    }

    @Override
    public SupplyRelationShip findOneBySupplyRelationShipId(Long id) {
        return supplyRelationShipRepository.findById(id).get();
    }

    @Override
    public void deleteOneBySupplyRelationShipId(Long id) {
        supplyRelationShipRepository.deleteById(id);
    }

    @Override
    public Iterable<SupplyRelationShip> findAllSupplyRelationShip() {
        return supplyRelationShipRepository.findAll();
    }

    @Override
    public List<SupplyRelationShip> findAllSupply() {
        List<SupplyRelationShip> supplyRelationShipList = new ArrayList<>();
        Driver driver = GraphDatabase.driver(neo4jProperty.getUrl(), AuthTokens.basic(neo4jProperty.getName(), neo4jProperty.getPassword()));
        Session session = driver.session();
        Map<String ,Object> map = new HashMap<>();
        map.put("nodeId","node-0");
        String  cql = "match(p:CompanyGraph{NodeId:{nodeId}})-[r]-(c:SupplyGraph) return p,r,c";
        List<SupplyRelationShip> supplyRelationShipList1 = getSupplyRelationShipList(session, cql, map, true);
        supplyRelationShipList.addAll(supplyRelationShipList1);
        if (supplyRelationShipList1 != null && supplyRelationShipList1.size()>0){
            for (SupplyRelationShip supplyRelationShip: supplyRelationShipList1){
                Map<String ,Object> mapChildren = new HashMap<>();
                mapChildren.put("nodeId",supplyRelationShip.getTarget());
                String  cqls = "match(p:CompanyGraph{NodeId:{nodeId}})-[r]-(c:SupplyGraph) return p,r,c";
                List<SupplyRelationShip> supplyRelationShipList2 = getSupplyRelationShipList(session,cqls,mapChildren,false);
                supplyRelationShipList.addAll(supplyRelationShipList2);
            }
        }
        return supplyRelationShipList;
    }

    @Override
    public List<SupplyRelationShip> findASupplyByNodeId(String nodeId) {
        List<SupplyRelationShip> supplyRelationShipList = new ArrayList<>();
        Driver driver = GraphDatabase.driver(neo4jProperty.getUrl(), AuthTokens.basic(neo4jProperty.getName(), neo4jProperty.getPassword()));
        Session session = driver.session();
        Map<String ,Object> map = new HashMap<>();
        map.put("nodeId",nodeId);
        String  cql = "match(p:CompanyGraph{NodeId:'node-0'})-[r]-(c:SupplyGraph) where c.NodeId = {nodeId} return p,r,c";
        List<SupplyRelationShip> supplyRelationShipList1 = getSupplyRelationShipList(session, cql,map,true);
        supplyRelationShipList.addAll(supplyRelationShipList1);
        if (supplyRelationShipList1 != null && supplyRelationShipList1.size()>0){
            for (SupplyRelationShip supplyRelationShip: supplyRelationShipList1){
                Map<String ,Object> mapC = new HashMap<>();
                mapC.put("nodeId",supplyRelationShip.getTarget());
                String cqls = "match(p:SupplyGraph{NodeId:'{nodeId}'})-[r]-(c:SupplyGraph) return p,r,c";
                List<SupplyRelationShip> supplyRelationShipList2 = getSupplyRelationShipList(session,cqls,mapC,false);
                supplyRelationShipList.addAll(supplyRelationShipList2);
            }
        }
        return supplyRelationShipList;
    }

    @Override
    public List<SupplyRelationShip> findByNodeId(String nodeId) {
        return supplyRelationShipRepository.findByNodeId(nodeId);
    }


    /**
     * 组合对应关系
     * @param session
     * @param cql
     * @param flag
     * @return
     */
    private List<SupplyRelationShip> getSupplyRelationShipList(Session session, String cql, Map<String , Object > map, boolean flag){
        StatementResult result = session.run(cql, map);
        List<SupplyRelationShip> supplyRelationShipList = new ArrayList<>();
        while (result.hasNext()) {
            Record record = result.next();
            Map<String, Object> date = record.asMap();// 这里面存的是这个关系的键值对，其实就是起始节点，关系，结束节点
            Map<String, Object> nodeMap = new HashMap<>();
            for (String key : date.keySet()) {
                Object object = date.get(key);
                if (key.startsWith("p")) {
                    InternalNode data = (InternalNode) object;// 强制转换
                    long nodeId = data.id();
                    Map<String, Object> nodeDataMap = new HashMap<>();
                    Map<String, Object> data1 = data.asMap();// 添加节点的属性
                    for (String key1 : data1.keySet()) {
                        nodeDataMap.put(key1, data1.get(key1));
                    }
                    nodeDataMap.put("id", nodeId);
                    CompanyGraph companyGraph = JSON.parseObject(JSON.toJSONString(nodeDataMap), CompanyGraph.class);
                    nodeMap.put("companyGraph", companyGraph);
                    if (flag){
                        //添加源节点
                        supplyRelationShipList.add(getSourceNode(companyGraph));
                    }
                } else if (key.startsWith("r")) {
                    Relationship relationship = (Relationship) object;
                    Map<String, Object> data2 = relationship.asMap();// 添加关系的属性
                    long id = relationship.id();
                    for (String key1 : data2.keySet()) {
                        nodeMap.put(key1, data2.get(key1));
                    }
                    nodeMap.put("id", id);
                } else if (key.startsWith("c")) {
                    InternalNode data = (InternalNode) object;// 强制转换
                    long nodeId = data.id();
                    Map<String, Object> nodeDataMapChildren = new HashMap<>();
                    Map<String, Object> data1 = data.asMap();// 添加节点的属性
                    for (String key1 : data1.keySet()) {
                        nodeDataMapChildren.put(key1, data1.get(key1));
                    }
                    nodeDataMapChildren.put("id", nodeId);
                    SupplyGraph supplyGraph = JSON.parseObject(JSON.toJSONString(nodeDataMapChildren), SupplyGraph.class);
                    nodeMap.put("supplyGraph", supplyGraph);
                }
            }
            SupplyRelationShip supplyRelationShip = JSON.parseObject(JSON.toJSONString(nodeMap), SupplyRelationShip.class);
            supplyRelationShipList.add(supplyRelationShip);
        }
        Set<SupplyRelationShip> set = new HashSet<>();
        set.addAll(supplyRelationShipList);
        supplyRelationShipList.clear();
        supplyRelationShipList.addAll(set);
        return supplyRelationShipList;
    }

    /**
     * 添加源节点
     * @param companyGraph
     * @return
     */
    private SupplyRelationShip getSourceNode(CompanyGraph companyGraph){
        SupplyRelationShip supplyRelationShip1 = new SupplyRelationShip();
        supplyRelationShip1.setIndexName(companyGraph.getFullName());
        supplyRelationShip1.setSource(companyGraph.getNodeId());
        supplyRelationShip1.setTarget(companyGraph.getNodeId());
        supplyRelationShip1.setCompanyGraph(companyGraph);
        SupplyGraph supplyGraph = new SupplyGraph();
        supplyGraph.setNodeId(companyGraph.getNodeId());
        supplyGraph.setName(companyGraph.getFullName());
        supplyGraph.setType(companyGraph.getType());
        supplyGraph.setIndustry(companyGraph.getIndustry());
        supplyGraph.setPhone(companyGraph.getPhone());
        supplyGraph.setId(companyGraph.getId());
        supplyRelationShip1.setSupplyGraph(supplyGraph);
        return supplyRelationShip1;
    }

    @Override
    public void makeDataBySupplyRelationShip() {
        makeDate();
    }

    @Override
    public void makeDataMoreBySupplyRelationShip() {
        makeDateMore();
    }

    /**
     * 查询节点
     * @return
     */
    private List<SupplyRelationShip> queryNode(SupplyRelationShip supplyRelationShip){
        List<SupplyRelationShip> supplyRelationShipList = null;
        String cql = "match(c:CompanyGraph)-[r]-(s:SupplyGraph) where c.NodeId = {source} and s.NodeId = {target} return r";
        Map<String , Object> map = new HashMap<>();
        map.put("source",supplyRelationShip.getSource());
        map.put("target",supplyRelationShip.getTarget());
        Driver driver = GraphDatabase.driver(neo4jProperty.getUrl(), AuthTokens.basic(neo4jProperty.getName(), neo4jProperty.getPassword()));
        Session session = driver.session();
        supplyRelationShipList = getSupplyRelationShipList(session, cql,map,false);
        return supplyRelationShipList;
    }


    //造数据
    public void makeDate(){
        String[] arr = {"A","B","C","D","E","F","G","H","I","J"};
        Integer num = 1;
        for (String a:arr){
            SupplyRelationShip supplyRelationShip = new SupplyRelationShip();
            CompanyGraph companyGraph = new CompanyGraph();
            SupplyGraph supplyGraph = new SupplyGraph();
            supplyRelationShip.setIndexName("供应商"+a+"(node-"+num+")");
            supplyRelationShip.setSource("node-0");
            supplyRelationShip.setTarget("node-"+num);
            CompanyGraph companyGraph1 = companyGraphService.findOneByNodeId("node-0");
            if (companyGraph1 != null){
                companyGraph.setId(companyGraph1.getId());
                companyGraph.setNodeId(companyGraph1.getNodeId());
                companyGraph.setType(companyGraph1.getType());
                companyGraph.setIndustry(companyGraph1.getIndustry());
                companyGraph.setPhone(companyGraph1.getPhone());
                companyGraph.setFullName(companyGraph1.getFullName());
                SupplyGraph supplyGraph1 = supplyGraphService.findOneByNodeId("node-"+num);
                if (supplyGraph1 != null){
                    supplyGraph.setId(supplyGraph1.getId());
                    supplyGraph.setNodeId(supplyGraph1.getNodeId());
                    supplyGraph.setType(supplyGraph1.getType());
                    supplyGraph.setIndustry(supplyGraph1.getIndustry());
                    supplyGraph.setPhone(supplyGraph1.getPhone());
                    supplyGraph.setName(supplyGraph1.getName());
                } else {
                    supplyGraph.setNodeId("node-"+num);
                    supplyGraph.setType("A级供应商");
                    supplyGraph.setIndustry("传统行业");
                    supplyGraph.setPhone("123456789");
                    supplyGraph.setName(a);
                }
                supplyRelationShip.setCompanyGraph(companyGraph);
                supplyRelationShip.setSupplyGraph(supplyGraph);
                List<SupplyRelationShip> supplyRelationShipList = queryNode(supplyRelationShip);
                if (supplyRelationShipList == null || supplyRelationShipList.size() == 0){
                    this.addSupplyRelationShip(supplyRelationShip);
                }
            }
            num++;
        }
    }

    //造数据
    public void makeDateMore(){
        String[] arr = {"A","B","C","D","E","F","G","H","I","J"};
        Integer sum = 11;
        Integer num = 1;
        for(String s:arr){
            SupplyGraph supplyGraph1 = supplyGraphService.findOneByNodeId("node-"+num);
            for (String a:arr){
                SupplyRelationShip supplyRelationShip = new SupplyRelationShip();
                CompanyGraph companyGraph = new CompanyGraph();
                SupplyGraph supplyGraph = new SupplyGraph();
                supplyRelationShip.setSource("node-"+num);
                supplyRelationShip.setIndexName("供应商"+s+"==》二级供应商"+a+"(node-"+sum+")");
                supplyRelationShip.setTarget("node-"+sum);
                companyGraph.setId(supplyGraph1.getId());
                companyGraph.setNodeId(supplyGraph1.getNodeId());
                companyGraph.setType(supplyGraph1.getType());
                companyGraph.setIndustry(supplyGraph1.getIndustry());
                companyGraph.setPhone(supplyGraph1.getPhone());
                companyGraph.setFullName(supplyGraph1.getName());
                SupplyGraph supplyGraph2 = supplyGraphService.findOneByNodeId("node-"+sum);
                if (supplyGraph2 != null){
                    supplyGraph.setId(supplyGraph2.getId());
                    supplyGraph.setNodeId(supplyGraph2.getNodeId());
                    supplyGraph.setType(supplyGraph2.getType());
                    supplyGraph.setIndustry(supplyGraph2.getIndustry());
                    supplyGraph.setPhone(supplyGraph2.getPhone());
                    supplyGraph.setName(supplyGraph2.getName());
                } else {
                    supplyGraph.setNodeId("node-"+sum);
                    supplyGraph.setType("B级供应商");
                    supplyGraph.setIndustry("传统行业");
                    supplyGraph.setPhone("123456789");
                    supplyGraph.setName(a);
                }
                supplyRelationShip.setCompanyGraph(companyGraph);
                supplyRelationShip.setSupplyGraph(supplyGraph);
                List<SupplyRelationShip> supplyRelationShipList = queryNode(supplyRelationShip);
                if (supplyRelationShipList == null || supplyRelationShipList.size() == 0){
                    this.addSupplyRelationShip(supplyRelationShip);
                }
                sum ++;
            }
            num ++;
        }
    }
}